package com.ta.gulimall.coupon.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ta.gulimall.common.utils.RedisUtil;
import com.ta.gulimall.coupon.constant.CouponConstants;
import com.ta.gulimall.coupon.service.SeckillSkuRelationService;
import com.ta.gulimall.coupon.view.vo.SeckillSessionWithSkus;
import com.ta.gulimall.coupon.view.vo.SeckillSkuRedisVo;
import com.ta.gulimall.coupon.view.vo.SeckillSkuVo;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ta.gulimall.common.utils.system.PageUtils;
import com.ta.gulimall.common.utils.system.Query;

import com.ta.gulimall.coupon.dao.SeckillSessionDao;
import com.ta.gulimall.coupon.entity.SeckillSessionEntity;
import com.ta.gulimall.coupon.service.SeckillSessionService;


@Service("seckillSessionService")
public class SeckillSessionServiceImpl extends ServiceImpl<SeckillSessionDao, SeckillSessionEntity> implements SeckillSessionService {
    @Autowired
    SeckillSkuRelationService seckillSkuRelationService;
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    RedissonClient redissonClient;
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SeckillSessionEntity> page = this.page(
                new Query<SeckillSessionEntity>().getPage(params),
                new QueryWrapper<SeckillSessionEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public List<SeckillSkuRedisVo> querySeckillGoods() {

        //秒杀场次信息
        LambdaQueryWrapper<SeckillSessionEntity> wrapper = new LambdaQueryWrapper<SeckillSessionEntity>()
                .ge(SeckillSessionEntity::getStartTime, LocalDateTime.now());
        List<SeckillSessionEntity> seckillSessionList = list(wrapper);
        Map<Long, SeckillSessionEntity> seckillSessionMap = seckillSessionList.stream().collect(Collectors.toMap(
                SeckillSessionEntity::getId,
                Function.identity()
        ));

        if (CollUtil.isEmpty(seckillSessionMap)) {
            return null;
        }
        //秒杀场次Id
        List<Long> sessionIds = new ArrayList<>(seckillSessionMap.keySet());
        Map<Long, List<SeckillSkuVo>> seckillSkuMap = seckillSkuRelationService.querySessionGoods(sessionIds);

        List<SeckillSkuRedisVo> seckillSkuRedisVoList = seckillSkuMap.entrySet().stream()
                .map(seckillSku -> {
                    return seckillSku.getValue().stream().map(seckillSkuVo -> {
                        SeckillSessionEntity seckillSession = seckillSessionMap.get(seckillSkuVo.getPromotionSessionId());
                        return SeckillSkuRedisVo.builder()
                                .promotionSessionId(seckillSku.getKey())
                                .skuId(seckillSkuVo.getSkuId())
                                .randomCode(UUID.randomUUID().toString().replaceAll("-", ""))
                                .seckillPrice(seckillSkuVo.getSeckillPrice())
                                .seckillCount(seckillSkuVo.getSeckillCount())
                                .startTime(seckillSession.getStartTime())
                                .endTime(seckillSession.getEndTime())
                                .build();
                    }).collect(Collectors.toList());
                })
                .flatMap(Collection::stream)
                .collect(Collectors.toList());

        return seckillSkuRedisVoList;
    }

    @Override
    public void seckillRequest(Map<String, Object> params) {
        String sessionId = (String) params.get("sessionId");
        String skuId = (String) params.get("skuId");
        String token = (String) params.get("token");

        SeckillSkuRedisVo skuRedisVo = redisUtil.hget(CouponConstants.REDIS_SECKILL_GOODS, sessionId + ":" + skuId, SeckillSkuRedisVo.class);
        if (skuRedisVo == null) {
            throw new RuntimeException("场次已经结束");
        }

        if (!skuRedisVo.getRandomCode().equals(token)) {
            throw new RuntimeException("非法的秒杀请求");
        }

        RSemaphore semaphore = redissonClient.getSemaphore(CouponConstants.REDIS_SECKILL_SEMAPHORE + ":" + sessionId + skuId);

        int count = semaphore.availablePermits();
        if (count == 0) {
            throw new RuntimeException("已抢完");
        }

        boolean tryAcquire = semaphore.tryAcquire();
        if (tryAcquire) {
            //秒杀成功 发送mq消息
        }else{
            throw new RuntimeException("秒杀失败");
        }
    }


}